namespace DCHealthCheck.DomainModel {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Diagnostics;
    using System.Text; 
    #endregion

    [Table("TimeSyncInfo")]
    public class TimeSyncInfo : ITimeSyncInfo, IObjectWithState, IValidatableObject {

        #region Members
        #region Max length fields
        public static readonly int LeapIndicatorMaxLength = 255;
        public static readonly int StratumMaxLength = 255;
        public static readonly int PrecisionMaxLength = 255;
        public static readonly int RootDelayMaxLength = 255;
        public static readonly int RootDispersionMaxLength = 255;
        public static readonly int PollIntervalMaxLength = 255;
        public static readonly int PhaseOffsetMaxLength = 255;
        public static readonly int ClockRateMaxLength = 255;
        public static readonly int StateMachineMaxLength = 255;
        public static readonly int TimeSourceFlagsMaxLength = 255;
        public static readonly int ServerRoleMaxLength = 255;
        public static readonly int LastSyncErrorMaxLength = 255;
        public static readonly int TimeSinceLastGoodSyncMaxLength = 255;
        public static readonly int SourceMaxLength = 255;
        public static readonly int SourceIPAddressMaxLength = 255;
        #endregion

        public virtual string ClockRate { get; set; }

        public static readonly string CSVHeader =
            "DCName,Domain,ADSite,OSVersion,HealthCheckDate," +
            "ClockRate,LastSuccessfulSync,LastSyncError,LeapIndicator,PhaseOffset,PollInterval,Precision,RootDelay,RootDispersion,ServerRole," +
            "Source,SourceIPAddress,StateMachine,Stratum,TimeSinceLastGoodSync,TimeSourceFlags";

        [Key]
        [ForeignKey("SystemInfo")]
        public virtual Guid Id { get; set; }

        public virtual DateTime LastSuccessfulSync { get; set; }

        public virtual string LastSyncError { get; set; }

        public virtual string LeapIndicator { get; set; }

        public virtual string PhaseOffset { get; set; }

        public virtual string PollInterval { get; set; }

        public virtual string Precision { get; set; }

        public virtual string RootDelay { get; set; }

        public virtual string RootDispersion { get; set; }

        public virtual string ServerRole { get; set; }

        public virtual string Source { get; set; }

        public virtual string SourceIPAddress { get; set; }

        public virtual string StateMachine { get; set; }

        public virtual string Stratum { get; set; }

        public virtual string TimeSinceLastGoodSync { get; set; }

        public virtual string TimeSourceFlags { get; set; }

        #region Related Entities
        public virtual SystemInfo SystemInfo {
            get { return systemInfo; }
            set {
                systemInfo = value;

                if (systemInfo != null) {
                    if (this.Id != systemInfo.Id) {
                        this.Id = systemInfo.Id;
                    };
                }
            }
        }
        private SystemInfo systemInfo;
        #endregion

        #region NotMapped properties
        [NotMapped]
        public DetachedState DetachedState { get; set; }

        [NotMapped]
        public Object EntityKey { get { return this.Id; } }

        [NotMapped]
        public Dictionary<string, object> StartingOriginalValues { get; set; }
        #endregion 
        #endregion

        #region Constructor
        public TimeSyncInfo() {
            this.ClockRate = string.Empty;
            this.LastSyncError = string.Empty;
            this.LeapIndicator = string.Empty;
            this.PhaseOffset = string.Empty;
            this.PollInterval = string.Empty;
            this.Precision = string.Empty;
            this.RootDelay = string.Empty;
            this.RootDispersion = string.Empty;
            this.ServerRole = string.Empty;
            this.Source = string.Empty;
            this.SourceIPAddress = string.Empty;
            this.StateMachine = string.Empty;
            this.Stratum = string.Empty;
            this.TimeSinceLastGoodSync = string.Empty;
            this.TimeSourceFlags = string.Empty;
        } 
        #endregion

        #region Methods
        public string ToCSVString() {
            var info = new StringBuilder();

            #region DC Info
            if ((this.SystemInfo != null) && (this.SystemInfo.DomainController != null)) {
                info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.SamAccountNameFriendly);
                info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.NetbiosDomain);
                info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.ADSite);
                info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.OSVersion);
            }
            else {
                info.Append(",,,,");
            }
            #endregion
            #region DateTime Info
            if (this.SystemInfo != null) {
                info.AppendFormat("\"{0}\",", this.SystemInfo.CheckDateTimeUTC.ToString("yyyy-MM-dd HH:mm"));
            }
            else {
                info.Append(",");
            }
            #endregion

            info.AppendFormat("\"{0}\",", this.ClockRate);
            info.AppendFormat("\"{0}\",", this.LastSuccessfulSync);
            info.AppendFormat("\"{0}\",", this.LastSyncError);
            info.AppendFormat("\"{0}\",", this.LeapIndicator);
            info.AppendFormat("\"{0}\",", this.PhaseOffset);
            info.AppendFormat("\"{0}\",", this.PollInterval);
            info.AppendFormat("\"{0}\",", this.Precision);
            info.AppendFormat("\"{0}\",", this.RootDelay);
            info.AppendFormat("\"{0}\",", this.RootDispersion);
            info.AppendFormat("\"{0}\",", this.ServerRole);
            info.AppendFormat("\"{0}\",", this.Source);
            info.AppendFormat("\"{0}\",", this.SourceIPAddress);
            info.AppendFormat("\"{0}\",", this.StateMachine);
            info.AppendFormat("\"{0}\",", this.TimeSinceLastGoodSync);
            info.AppendFormat("\"{0}\",", this.TimeSourceFlags);

            return info.ToString();
        }

        [DebuggerStepThroughAttribute]
        public override string ToString() {
            var info = new StringBuilder();

            info.Append("TimeSyncInfo: ");
            if ((this.SystemInfo != null) && (this.SystemInfo.DomainController != null) && (this.SystemInfo.DomainController.DNSName != null)) {
                info.AppendFormat("SystemInfo DC: {1}; ", this.SystemInfo.DomainController.DNSName);
            }
            info.AppendFormat("Source: {0}", this.Source);

            return info.ToString();
        }

        public string ToVerboseString() {
            var info = new StringBuilder();

            info.AppendFormat("DC: {0}; ", (this.SystemInfo != null) && (this.SystemInfo.DomainController != null) && (this.SystemInfo.DomainController.DNSName != null) ? this.SystemInfo.DomainController.DNSName : "NULL");
            info.AppendFormat("HealthCheck Date: {0}; ", this.SystemInfo != null ? this.SystemInfo.CheckDateTimeUTC.ToString("yyyy-MMM-dd") : "N/A");
            info.AppendFormat("Source: {0}; ", this.Source != null ? this.Source : "NULL");
            info.AppendFormat("Precision: {0}; ", this.Precision != null ? this.Precision : "NULL");
            info.AppendFormat("Time since last successful sync: {0}", !string.IsNullOrWhiteSpace(this.TimeSinceLastGoodSync) ? this.TimeSinceLastGoodSync : "N/A");

            return info.ToString();
        }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
            // add entity to SystemInfo, let DetectChanges perform relationship fixup
            if (this.Id == Guid.Empty) {
                yield return new ValidationResult(
                    "Id is required.", new[] { "Id" });
            }

            if (this.DetachedState != DetachedState.Deleted) {
                if (this.SystemInfo == null) {
                    yield return new ValidationResult(
                        "SystemInfo is required.", new[] { "SystemInfo" });
                }

                if (this.ClockRate == null) {
                    yield return new ValidationResult(
                        "ClockRate is required.", new[] { "ClockRate" });
                }
                else {
                    if (this.ClockRate.Length > ClockRateMaxLength) {
                        yield return new ValidationResult(string.Format("ClockRate length: {0} exceeds max length: {1}",
                            this.ClockRate.Length, ClockRateMaxLength), new[] { "ClockRate" });
                    }
                }

                if (this.LastSyncError == null) {
                    yield return new ValidationResult(
                        "LastSyncError is required.", new[] { "LastSyncError" });
                }
                else if (this.LastSyncError.Length > LastSyncErrorMaxLength) {
                    yield return new ValidationResult(string.Format("LastSyncError length: {0} exceeds max length: {1}",
                        this.LastSyncError.Length, LastSyncErrorMaxLength), new[] { "LastSyncError" });
                }

                if (this.LeapIndicator == null) {
                    yield return new ValidationResult(
                        "LeapIndicator is required.", new[] { "LeapIndicator" });
                }
                else if (this.LeapIndicator.Length > LeapIndicatorMaxLength) {
                    yield return new ValidationResult(string.Format("LeapIndicator length: {0} exceeds max length: {1}",
                        this.LeapIndicator.Length, LeapIndicatorMaxLength), new[] { "LeapIndicator" });
                }

                if (this.PhaseOffset == null) {
                    yield return new ValidationResult(
                        "PhaseOffset is required.", new[] { "PhaseOffset" });
                }
                else if (this.PhaseOffset.Length > PhaseOffsetMaxLength) {
                    yield return new ValidationResult(string.Format("PhaseOffset length: {0} exceeds max length: {1}",
                        this.PhaseOffset.Length, PhaseOffsetMaxLength), new[] { "PhaseOffset" });
                }

                if (this.PollInterval == null) {
                    yield return new ValidationResult(
                        "PollInterval is required.", new[] { "PollInterval" });
                }
                else if (this.PollInterval.Length > PollIntervalMaxLength) {
                    yield return new ValidationResult(string.Format("PollInterval length: {0} exceeds max length: {1}",
                        this.PollInterval.Length, PollIntervalMaxLength), new[] { "PollInterval" });
                }

                if (this.Precision == null) {
                    yield return new ValidationResult(
                        "Precision is required.", new[] { "Precision" });
                }
                else if (this.Precision.Length > PrecisionMaxLength) {
                    yield return new ValidationResult(string.Format("Precision length: {0} exceeds max length: {1}",
                        this.Precision.Length, PrecisionMaxLength), new[] { "Precision" });
                }

                if (this.RootDelay == null) {
                    yield return new ValidationResult(
                        "RootDelay is required.", new[] { "RootDelay" });
                }
                else if (this.RootDelay.Length > RootDelayMaxLength) {
                    yield return new ValidationResult(string.Format("RootDelay length: {0} exceeds max length: {1}",
                        this.RootDelay.Length, RootDelayMaxLength), new[] { "RootDelay" });
                }

                if (this.RootDispersion == null) {
                    yield return new ValidationResult(
                        "RootDispersion is required.", new[] { "RootDispersion" });
                }
                else if (this.RootDispersion.Length > RootDispersionMaxLength) {
                    yield return new ValidationResult(string.Format("RootDispersion length: {0} exceeds max length: {1}",
                        this.RootDispersion.Length, RootDispersionMaxLength), new[] { "RootDispersion" });
                }

                if (this.ServerRole == null) {
                    yield return new ValidationResult(
                        "ServerRole is required.", new[] { "ServerRole" });
                }
                else if (this.ServerRole.Length > ServerRoleMaxLength) {
                    yield return new ValidationResult(string.Format("ServerRole length: {0} exceeds max length: {1}",
                        this.ServerRole.Length, ServerRoleMaxLength), new[] { "ServerRole" });
                }

                if (this.Source == null) {
                    yield return new ValidationResult(
                        "Source is required.", new[] { "Source" });
                }
                else if (this.Source.Length > SourceMaxLength) {
                    yield return new ValidationResult(string.Format("Source length: {0} exceeds max length: {1}",
                        this.Source.Length, SourceMaxLength), new[] { "Source" });
                }

                if (this.SourceIPAddress == null) {
                    yield return new ValidationResult(
                        "SourceIPAddress is required.", new[] { "SourceIPAddress" });
                }
                else if (this.SourceIPAddress.Length > SourceIPAddressMaxLength) {
                    yield return new ValidationResult(string.Format("SourceIPAddress length: {0} exceeds max length: {1}",
                        this.SourceIPAddress.Length, SourceIPAddressMaxLength), new[] { "SourceIPAddress" });
                }

                if (this.StateMachine == null) {
                    yield return new ValidationResult(
                        "StateMachine is required.", new[] { "StateMachine" });
                }
                else if (this.StateMachine.Length > StateMachineMaxLength) {
                    yield return new ValidationResult(string.Format("StateMachine length: {0} exceeds max length: {1}",
                        this.StateMachine.Length, StateMachineMaxLength), new[] { "StateMachine" });
                }

                if (string.IsNullOrWhiteSpace(this.Stratum)) {
                    yield return new ValidationResult(
                        "Stratum is required.", new[] { "Stratum" });
                }
                else if (this.Stratum.Length > StratumMaxLength) {
                    yield return new ValidationResult(string.Format("Stratum length: {0} exceeds max length: {1}",
                        this.Stratum.Length, StratumMaxLength), new[] { "Stratum" });
                }

                if (this.TimeSinceLastGoodSync == null) {
                    yield return new ValidationResult(
                        "TimeSinceLastGoodSync is required.", new[] { "TimeSinceLastGoodSync" });
                }
                else if (this.TimeSinceLastGoodSync.Length > TimeSinceLastGoodSyncMaxLength) {
                    yield return new ValidationResult(string.Format("TimeSinceLastGoodSync length: {0} exceeds max length: {1}",
                        this.TimeSinceLastGoodSync.Length, TimeSinceLastGoodSyncMaxLength), new[] { "TimeSinceLastGoodSync" });
                }

                if (this.TimeSourceFlags == null) {
                    yield return new ValidationResult(
                        "TimeSourceFlags is required.", new[] { "TimeSourceFlags" });
                }
                else if (this.TimeSourceFlags.Length > TimeSourceFlagsMaxLength) {
                    yield return new ValidationResult(string.Format("TimeSourceFlags length: {0} exceeds max length: {1}",
                        this.TimeSourceFlags.Length, TimeSourceFlagsMaxLength), new[] { "TimeSourceFlags" });
                }
            } // if (this.DetachedState != State.Deleted)
        }  
        #endregion
        
    }
}
